import threading
import time

import paho.mqtt.client as mqtt
import matplotlib.pyplot as plt
from datetime import datetime

# 初始化图形
fig, ax = plt.subplots(figsize=(15, 8))

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']

# 初始化时间和温度列表
times = []
temps = []

# 设置初始显示范围
ax.set_xlim(0, 10)
ax.set_ylim(10, 40)

# 设置图形标题和轴标签
ax.set_title('温度时间图')
ax.set_xlabel('时间')
ax.set_ylabel('温度')

# 创建初始空白线条
line, = ax.plot([], [], 'b-')


def time_wrapper(func):  # 使用多线程装饰器
    def wrapper(*args, **kwargs):
        thread = threading.Thread(target=func, args=args, kwargs=kwargs)
        thread.start()
        return thread

    return wrapper

@time_wrapper
def get_data():
    # 判断是否连接上mqtt服务器
    def on_connect(self, client, userdata, flags, rc):
        """连接回调函数"""
        if flags == 0:
            print("Connected to MQTT successfully!")
        else:
            print("Failed to connect, return code {0}".format(flags))

    # 订阅的主题中有新消息发布，则触发回调函数打印
    def on_message(client, userdata, msg):
        """消息回调函数"""
        print(msg.topic + " " + ":" + " " + msg.payload.decode())
        # 获取当前温度
        temp = int(msg.payload.decode())
        # 获取当前时间
        now_time = datetime.now()
        time = now_time.strftime('%Y-%m-%d %H:%M:%S')
        #  # 控制只保留最新的8个数据
        if len(times) > 8:
            temps.pop(0)
            times.pop(0)
        temps.append(temp)
        times.append(time)

    # 创建客户端实例对象，参数为回调API版本，客户端的ID
    client = mqtt.Client(callback_api_version=mqtt.CallbackAPIVersion.VERSION2, client_id="python_mqtt")
    client.on_connect = on_connect  # 设置回调函数
    client.on_message = on_message  # 设置回调函数
    client.connect("192.168.92.220", 1883, 60)  # 连接服务器，参数(ip,端口,超时时间)
    client.subscribe("mqtt_esp32_project_DHT11")  # 订阅主题
    client.loop_forever()  # 开启一个循环，保持与服务器连接，持续接收和处理信息



def show_plt():
    global times, temps
    # 循环更新图形
    time.sleep(2)
    while True:
        # 更新线条数据
        line.set_data(times, temps)
        # 重新设置 x 轴范围
        if times is not None and times is not None:
            ax.set_xlim(min(times), max(times))
            # 重新绘制图形
            fig.canvas.draw()
        # 暂停 3 秒
        plt.pause(3)


if __name__ == '__main__':
    get_data()  # 获取数据
    show_plt()  # 显示图形
